package com.my_musc_service.interceptor;


import com.alibaba.fastjson.JSON;
import com.my_musc_service.common.R;
import com.my_musc_service.constants.SessionKeys;
import com.my_musc_service.entity.User;
import com.my_musc_service.exception.CustomException;
import com.my_musc_service.utils.JwtUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;

//目的是获取userId 或者 userKey
@Component
public class LoginInterceptor implements HandlerInterceptor {
    public static final ThreadLocal<User> THREAD_LOCAL = new ThreadLocal<>();

    @Value("${server.port}")
    private String port;

    public void responsePrint(HttpServletResponse response, String message) throws IOException {
        response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        response.setHeader("Content-Type", "application/json;charset=utf-8");
        PrintWriter writer = response.getWriter();
        R r = R.error().message(message);
        writer.write(JSON.toJSONString(r));
        writer.flush();
        writer.close();
    }

    /**
     * 为解决多线程程序而生
     * 防止内存泄漏
     * threadLocal 底层是一个大的map，它进行存法数据时，是将线程的hash作为key值
     *
     * @return
     */
    public static User getUserInfo() {
        return THREAD_LOCAL.get();
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        User user = new User();
        //userId或者userKey 存在于cookie中
        String token = request.getHeader("auth-token");

        //判断前端传入token是否为空 ，为空拒绝登录
        if (StringUtils.isEmpty(token)) {
            responsePrint(response, "用户未登录");
            //使用OutputStream流输出中文
//            outputChineseByOutputStream(response);
            return false;
        }

        //判断token是否有效【30分钟有效期】
        if (!JwtUtils.checkJWT(token)) {
            responsePrint(response, "token失效,请重新登录");
            return false;
        }

        //解析token，获取userId
        try {
            Map<String, Object> infoFromToken = JwtUtils.parseJWT(token);

            Integer id = (Integer) infoFromToken.get("id");
            String nickname = (String) infoFromToken.get("nickname");
            String username = (String) infoFromToken.get("username");
            Integer sex = (Integer) infoFromToken.get("sex");
            String phone = (String) infoFromToken.get("phone");
            String headerImgUrl = (String) infoFromToken.get("headerImgUrl");

            user.setId(id);
            user.setUserName(username);
            user.setNickName(nickname);
            user.setSex(sex);
            user.setPhone(phone);
            user.setHeaderImgUrl(headerImgUrl);
        } catch (Exception e) {
            e.printStackTrace();
            throw new CustomException("jwt验证异常");
        }
        //把userInfo传给后续业务 TODO
        THREAD_LOCAL.set(user);

        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //防止内存泄露，必须删除，不然会造成线程不安全，因为在这里我们使用的是tomcat线程池
        //请求结束不代表线程结束
        THREAD_LOCAL.remove();
    }

}


//    /**
//     * 使用OutputStream流输出中文
//     * @param response
//     * @throws IOException
//     */
//    public void outputChineseByOutputStream(HttpServletResponse response) throws IOException {
//        /**使用OutputStream输出中文注意问题：
//         * 在服务器端，数据是以哪个码表输出的，那么就要控制客户端浏览器以相应的码表打开，
//         * 比如：outputStream.write("中国".getBytes("UTF-8"));//使用OutputStream流向客户端浏览器输出中文，以UTF-8的编码进行输出
//         * 此时就要控制客户端浏览器以UTF-8的编码打开，否则显示的时候就会出现中文乱码，那么在服务器端如何控制客户端浏览器以以UTF-8的编码显示数据呢？
//         * 可以通过设置响应头控制浏览器的行为，例如：
//         * response.setHeader("content-type", "text/html;charset=UTF-8");//通过设置响应头控制浏览器以UTF-8的编码显示数据
//         */
//
//        R r = R.error().message("用户未登录");
//        String data = JSON.toJSONString(r);
//
//        //获取OutputStream输出流
//        OutputStream outputStream = response.getOutputStream();
//        //通过设置响应头控制浏览器以UTF-8的编码显示数据，如果不加这句话，那么浏览器显示的将是乱码
//        response.setHeader("content-type", "text/html;charset=UTF-8");
//        /**
//         * data.getBytes()是一个将字符转换成字节数组的过程，这个过程中一定会去查码表，
//         * 如果是中文的操作系统环境，默认就是查找查GB2312的码表，
//         * 将字符转换成字节数组的过程就是将中文字符转换成GB2312的码表上对应的数字
//         * 比如： "中"在GB2312的码表上对应的数字是98
//         *         "国"在GB2312的码表上对应的数字是99
//         */
//        /**
//         * getBytes()方法如果不带参数，那么就会根据操作系统的语言环境来选择转换码表，如果是中文操作系统，那么就使用GB2312的码表
//         */
//        //将字符转换成字节数组，指定以UTF-8编码进行转换
//        byte[] dataByteArr = data.getBytes("UTF-8");
//        //使用OutputStream流向客户端输出字节数组
//        outputStream.write(dataByteArr);
//    }


//        String requestURI = request.getRequestURI();
//        String requestURINew = requestURI.substring(requestURI.indexOf("/")+1);
//        if("/music/login".equals(requestURI)|| "/music/register".equals(requestURI)){
//            //把userInfo传给后续业务 TODO
//            THREAD_LOCAL.set(user);
//            return true;
//        }
//        else if(requestURINew.matches("^music\\/\\d{4}.*")){
//            //把userInfo传给后续业务 TODO
//            THREAD_LOCAL.set(user);
//            return true;
//        }
//        else if("OPTIONS".equals(method)){
//            //把userInfo传给后续业务 TODO
//            THREAD_LOCAL.set(user);
//            return true;
//        }
